﻿//using System;
//using System.Collections.Concurrent;
//using System.Collections.Generic;
//using System.Threading.Tasks;
//using nRoute.Components.Composition.Adapters;
//using nRoute.Components.Mapping;
//using nRoute.Components.Messaging;
//using nRoute.Utilities;

//namespace nRoute.Components.Composition
//{
//    class ServiceCatalog
//    {

//        private const string CANNOT_RESOLVE_RESOURCE = "Cannot resolve resource of type {0}";
//        private const string CANNOT_RESOLVE_LOCATOR = "Cannot resolve locator for type {0}";
//        private const string CANNOT_RESOLVE_ON = "Could not resolve resource type on {0}";
//        private const string CANNOT_RESOLVE_IRESOURCELOCATOR = "Could not resolve IResourceLocator on {0}";

//        private readonly Type _invokerGenericType = typeof(ResourceInvoker<>);

//    #region Resources Static Methods

//        // Resource Related

//        public object GetResource(Type resourceType)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            var _resource = default(ResourceCatalog);
//            if (!_resourceCatalogs.TryGetValue(resourceType, out _resource))
//            {
                
//            }

//            return _resource;

//            // first we check our catalog
//            if (_resourceCatalogs.ContainsKey(resourceType)) 
//            {
//                return _resourceCatalogs[resourceType].ResolveResourceManager(false); 
//            }

//            // next we check our adapters
//            var _adapter = ResolveApplicableAdapter(resourceType);
//            if (_adapter != null)
//            {
//                return _adapter(resourceType).Resolve(null);
//            }
//            else
//            {
//                throw new InvalidOperationException(string.Format(CANNOT_RESOLVE_RESOURCE, resourceType.FullName));
//            }
//        }

//        public object GetResource(Type resourceType, string name)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            lock (_lock)
//            {
//                // first we check our catalog
//                if (_resourceCatalogs.ContainsKey(resourceType))
//                {
//                    return _resourceCatalogs[resourceType].ResolveResourceManager(name, true);       
//                }

//                // next we check our adapters
//                var _adapter = ResolveApplicableAdapter(resourceType);
//                if (_adapter != null)
//                {
//                    return _adapter(resourceType).Resolve(name);
//                }
//                else
//                {
//                    throw new InvalidOperationException(string.Format(CANNOT_RESOLVE_RESOURCE, resourceType.FullName));    
//                }
//            }
//        }

//        public bool TryGetResource(Type resourceType, out object resourceInstance)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            // by default
//            resourceInstance = null;

//            lock (_lock)
//            {
//                // first we check our catalog
//                if (_resourceCatalogs.ContainsKey(resourceType))
//                {
//                    resourceInstance = _resourceCatalogs[resourceType].ResolveResourceManager(false);
//                    if (resourceInstance != null) return true;
//                }

//                // first we check our adapters
//                var _adapter = ResolveApplicableAdapter(resourceType);
//                if (_adapter != null)
//                {
//                    resourceInstance = _adapter(resourceType).Resolve(null);
//                    return true;
//                }
//                else
//                {
//                    return false;
//                }
//            }
//        }

//        public bool TryGetResource(Type resourceType, string name, out object resourceInstance)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            // by default
//            resourceInstance = null;

//            lock (_lock)
//            {
//                // first we check our catalog
//                if (_resourceCatalogs.ContainsKey(resourceType))
//                {
//                    resourceInstance = _resourceCatalogs[resourceType].ResolveResourceManager(name, false);
//                    if (resourceInstance != null) return true;
//                }

//                // first we check our adapters
//                var _adapter = ResolveApplicableAdapter(resourceType);
//                if (_adapter != null)
//                {
//                    resourceInstance = _adapter(resourceType).Resolve(name);
//                    return true;
//                }
//                else
//                {
//                    return false;
//                }
//            }
//        }

//        // Locator Related

//        public IResourceManager GetResourceLocator(Type resourceType)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            lock (_lock)
//            {
//                if (!_resourceCatalogs.ContainsKey(resourceType)) throw new InvalidOperationException(
//                    string.Format(CANNOT_RESOLVE_LOCATOR, resourceType.FullName));
//                return _resourceCatalogs[resourceType].ResolveResourceLocator(false);
//            }
//        }

//        public IResourceManager GetResourceLocator(Type resourceType, string name)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            lock (_lock)
//            {
//                if (!_resourceCatalogs.ContainsKey(resourceType)) throw new InvalidOperationException(
//                    string.Format(CANNOT_RESOLVE_LOCATOR, resourceType.FullName));
//                return _resourceCatalogs[resourceType].ResolveResourceLocator(name, true);
//            }
//        }

//        public bool TryGetResourceLocator(Type resourceType, out IResourceManager resourceLocator)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            // by default
//            resourceLocator = null;

//            lock (_lock)
//            {
//                if (!_resourceCatalogs.ContainsKey(resourceType)) return false;
//                resourceLocator = _resourceCatalogs[resourceType].ResolveResourceLocator(false);
//                return (resourceLocator != null);
//            }
//        }

//        public bool TryGetResourceLocator(Type resourceType, string name, out IResourceManager resourceLocator)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            // by default
//            resourceLocator = null;

//            lock (_lock)
//            {
//                if (!_resourceCatalogs.ContainsKey(resourceType)) return false;
//                resourceLocator = _resourceCatalogs[resourceType].ResolveResourceLocator(name, false);
//                return (resourceLocator != null);
//            }
//        }

//        // Registration Related

//        public void RegisterAsKnownResourceType(Type resourceType)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            lock (_lock)
//            {
//                if (!_resourceCatalogs.ContainsKey(resourceType))
//                {
//                    // this creates the catalog if did not exist
//                    var _invoker = (ResourceInvoker)Activator.CreateInstance(_invokerGenericType.MakeGenericType(resourceType));
//                    var _catalog = _invoker.GetResourceCatalog();
//                    _catalog.IsKnownResource = true;
//                }
//            }
//        }

//        public bool IsResourceRegistered(Type resourceType)
//        {
//            return IsResourceRegistered(resourceType, true);
//        }

//        public bool IsResourceRegistered(Type resourceType, bool ensureHasDefaultResource)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            lock (_lock)
//            {
//                if (!_resourceCatalogs.ContainsKey(resourceType)) return false;
//                var _catalog = _resourceCatalogs[resourceType];
//                return (ensureHasDefaultResource) ? _catalog.IsAnyResourceRegistered() : _catalog.IsKnownResource;
//            }
//        }

//        public bool IsResourceRegistered(Type resourceType, string name)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");
//            Guard.ArgumentNotNullOrWhiteSpace(name, "name");

//            lock (_lock)
//            {
//                if (!_resourceCatalogs.ContainsKey(resourceType)) return false;
//                return _resourceCatalogs[resourceType].IsNamedResourceRegistered(name);
//            }
//        }

//        public bool IsResourceAdapterRegistered(Type resourceType)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            lock (_lock)
//            {
//                return (ResolveApplicableAdapter(resourceType) != null);
//            }
//        }

//        public bool IsResourceOrAdapterRegistered(Type resourceType)
//        {
//            return IsResourceOrAdapterRegistered(resourceType, null);
//        }

//        public bool IsResourceOrAdapterRegistered(Type resourceType, string name)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            if (string.IsNullOrEmpty(name) )
//            {
//                if (IsResourceRegistered(resourceType, true)) return true;
//            }
//            else
//            {
//                if (IsResourceRegistered(resourceType, name)) return true;
//            }
//            return IsResourceAdapterRegistered(resourceType);
//        }

//        public void SetDefaultResourceLocator(Type resourceType, string name)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");
//            Guard.ArgumentNotNullOrWhiteSpace(name, "name");

//            lock (_lock)
//            {
//                if (!_resourceCatalogs.ContainsKey(resourceType)) throw new InvalidOperationException(
//                    string.Format(CANNOT_RESOLVE_RESOURCE, resourceType.FullName));
//                 _resourceCatalogs[resourceType].SetDefaultResourceLocator(name);
//            }
//        }

//        public void RegisterResourceLocator(Type resourceType, IResourceManager locator, bool isDefault)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            lock (_lock) 
//            {
//                // we get the resource catalog
//                ResourceCatalog _resourceCatalog = null;
//                if (!_resourceCatalogs.TryGetValue(resourceType, out _resourceCatalog))
//                {
//                    // note_ we use activator because the classes are private and not public
//                    var _invoker = (ResourceInvoker)Activator.CreateInstance(_invokerGenericType.MakeGenericType(resourceType));
//                    _resourceCatalog = _invoker.GetResourceCatalog();
//                }

//                // we add to the listings
//                _resourceCatalog.RegisterResourceLocator(locator, isDefault);
//                if (!_resourceCatalog.IsKnownResource) _resourceCatalog.IsKnownResource = true;

//            }
//        }

//        public void UnregisterResourceLocator(Type resourceType, string name)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");
//            Guard.ArgumentNotNullOrWhiteSpace(name, "name");

//            lock (_lock)
//            {
//                // we get the resource catalog
//                ResourceCatalog _resourceCatalog = null;
//                if (!_resourceCatalogs.TryGetValue(resourceType, out _resourceCatalog))
//                {
//                   throw new InvalidOperationException("Cannot resolve resource of type " 
//                       + resourceType.FullName);
//                }

//                // we add to the listings
//                _resourceCatalog.UnregisterResource(name);
//            }
//        }

//#endregion

//#region Helpers

//        private Func<Type, ILocatorAdapter> ResolveApplicableAdapter(Type resourceType)
//        {
//            foreach (var _kv in _resourceAdapters)
//            {
//                // if an adapter predicate says yes, then we let it handle it
//                if (_kv.Key(resourceType))
//                {
//                    return _kv.Value;
//                }
//            }
//            return null;
//        }

//        internal IEnumerable<IResourceManager> GetResourceCatalog(Type resourceType)
//        {
//            Guard.ArgumentNotNull(resourceType, "resourceType");

//            lock (_lock)
//            {
//                if (!_resourceCatalogs.ContainsKey(resourceType)) return null;
//                return _resourceCatalogs[resourceType] as IEnumerable<IResourceManager>;
//            }
//        }

//#endregion

//#region Public Methods
        
//        // For Unresolved Mapping

//        public static void ThrowIfHasUnresolvedMapping()
//        {
//            lock (_lock)
//            {
//                if (_pendingMappings.Count > 0)
//                {
//                    throw new UnresolvedMappingsException(_pendingMappings[0].TargetType,
//                        _pendingMappings[0].ResourceAttribute.GetType());
//                }
//            }
//        }

//        public static void RegisterLocatorAdapter(Func<Type, bool> adapterPredicate, Func<Type, ILocatorAdapter> adapterFactory)
//        {
//            Guard.ArgumentNotNull(adapterPredicate, "adapterPredicate");
//            Guard.ArgumentNotNull(adapterFactory, "adapterFactory");

//            lock (_lock)
//            {
//                _resourceAdapters.Add(new KeyValuePair<Func<Type, bool>, Func<Type, ILocatorAdapter>>(adapterPredicate, adapterFactory));
//            }
//        }

//#endregion

//#region Nested Classes

//        private abstract class ResourceInvoker 
//        {
//            public abstract ResourceCatalog GetResourceCatalog();
//        }

//        private class ResourceInvoker<T>
//            : ResourceInvoker
//            where 
//                T : class
//        {
//            public override ResourceCatalog GetResourceCatalog()
//            {
//                return Resource<T>.Catalog;
//            }
//        }

//#endregion

//    }
//}
